package com.cbtx.tablet.device

import android.annotation.SuppressLint
import android.app.Presentation
import android.content.ContentResolver
import android.content.Context
import android.hardware.display.DisplayManager
import android.media.AudioManager
import android.os.Build
import android.os.Environment
import android.os.SystemClock
import android.text.TextUtils
import android.text.format.Time
import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import com.cbtx.utils.FileSizeUtil
import com.cbtx.utils.FileTool
import com.cbtx.utils.NetWorkUtil
import com.cbtx.utils.SimUtil
import com.xinchao.machine.digital_advertise.IBaseMachine
import java.io.*
import java.util.*
import kotlin.math.roundToLong

/**
 * author : joker.peng
 * e-mail : joker@fiture.com
 * date   : 2021/7/1 11:28 AM
 * desc   :
 */
@SuppressLint("NewApi")
class BaseMachine(var context: Context) : IMachine {

    private val TAG = "BaseMachine"

    private val UUID_PATH = Environment.getExternalStorageDirectory().absolutePath + File.separator + ".uuid"
    private var mUuid: String? = null

    override fun getModel(): String {
        return Build.MODEL
    } //所谓的机芯


    override fun SystemVersionName(): String? {
        return Build.VERSION.SDK
    }

    override fun SystemVersionCode(): Int {
        return Build.VERSION.SDK_INT
    }

    override fun getLocalMac(): String {
        var mac = getEthMac()
        if (TextUtils.isEmpty(mac)) {
            mac = getWlanMac()
            if (TextUtils.isEmpty(mac)) {
                mac = "02:00:00:00:00:00"
            }
        }
        return mac!!.toUpperCase()
    }

    override fun startCollectWifiProbe(
        collection_interval: Int,
        isShowMacInLogI: Boolean,
        listener: IBaseMachine.WifiProbeListener?
    ) {
        TODO("Not yet implemented")
    }

    override fun getLcdLightStatus(): Boolean {
        TODO("Not yet implemented")
    }

    override fun getWlanMac(): String? {
        val filePath = "/sys/class/net/wlan0/address"
        if (FileTool.isFileExist(filePath)) {
            var wlanMac = getInfoBySuCommand("cat $filePath")
            if (TextUtils.isEmpty(wlanMac)) {
                wlanMac = getFirstLine(filePath)
            }
            return wlanMac
        }
        return null
    }

    override fun getEthMac(): String? {
        return null
    }


    override fun getFrameworkVersion(): String? {
        var tmp = Build.DISPLAY
        if (!TextUtils.isEmpty(tmp) && tmp.contains("-")) {
            val tmps = tmp.split("-".toRegex()).toTypedArray()
            tmp = tmps[0].replace("v", "").replace("V", "").trim { it <= ' ' }
        }
        return tmp
    }

    override fun bootTime(): Long {
        return System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() / 1000000
    }

    override fun shotScreen(dir: String?, name: String?, displayId: Int): String {
        TODO("Not yet implemented")
    }


    override fun getDisplays(): Array<Display> {
        val mDisplayManager =
            context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
        return mDisplayManager.displays
    }

    override fun disable_watchdog(): Int {
        TODO("Not yet implemented")
    }

    override fun getDisplayCount(): Int {
        val displays = getDisplays()
        return displays?.size ?: 0
    }

    override fun downLTE() {
        TODO("Not yet implemented")
    }

    override fun getDisplayId(presentation: Presentation?): Int {
        return presentation?.display?.displayId ?: -1
    }

    override fun isMainDisplay(presentation: Presentation?): Boolean {
        return if (presentation == null) {
            false
        } else presentation.display.displayId == 0
    }

    override fun setSwitchStatus(isOpen: Boolean) {
        TODO("Not yet implemented")
    }

    override fun getCutScreen(): IntArray {
        TODO("Not yet implemented")
    }

    override fun isOtherDisplay(presentation: Presentation?): Boolean {
        return if (presentation == null) {
            false
        } else presentation.display.displayId != 0
    }

    override fun getFanStatus(): String {
        TODO("Not yet implemented")
    }

    override fun isValidUpdateZip(filePath: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun getDisplayWidth(display: Display): Int {
        val metrics = getDisPlayMetrics(display) ?: return 0
        return metrics.widthPixels
    }

    override fun getDisplayHeight(display: Display): Int {
        val metrics = getDisPlayMetrics(display) ?: return 0
        return metrics.heightPixels
    }

    override fun setVolume(vol: Int, type: Int) {
        if (vol < 0 || vol > 100) {
            return
        }
        val audioManager =
            context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val max = audioManager.getStreamMaxVolume(type)
        audioManager.setStreamVolume(type, Math.round(vol.toFloat() * max / 100), 0)
    }

    override fun enable_watchdog(): Int {
        TODO("Not yet implemented")
    }

    override fun setSwitchTime(onH: Int, onM: Int, offH: Int, offM: Int): Int {
        return 0
    }

    override fun feed_watchdog(): Int {
        TODO("Not yet implemented")
    }

    override fun upgrade(filePath: String?) {
        TODO("Not yet implemented")
    }

    override fun setFanStatus(isOn: Boolean) {
        TODO("Not yet implemented")
    }


    override fun power_off() {
        executeSuCommand("reboot -p")
    }

    override fun reboot() {
        executeSuCommand("reboot")
    }

    override fun isMobileDataEnable(): Boolean {
        TODO("Not yet implemented")
    }

    override fun upLTE() {
        TODO("Not yet implemented")
    }

    override fun getTotalMemory(): Long {
        val firstLine = firstLine2Number(getFirstLine("/proc/meminfo"))
        return if (TextUtils.isEmpty(firstLine)) {
            0
        } else firstLine.toLong() * 1024
        //为了方便格式化 所以乘以1024
    }

    override fun getTotalMemory(type: Int): String? {
        when (type) {
            0 -> return getTotalMemory().toString() + "B"
            1 -> return  "${getTotalMemory() / 1024}B"
            2 -> return  "${getTotalMemory() / 1024 / 1024}MB"
            3 -> return  "${(getTotalMemory().toFloat() / 1024 / 1024 / 1024 * 100).roundToLong().toDouble() / 100}GB"
            else -> {
            }
        }
        return null
    }

    override fun getSystemProperties(key: String): String? {
        return getInfoBySuCommand("getprop $key")
    }

    override fun setMobileDataEnable(enable: Boolean) {
        TODO("Not yet implemented")
    }

    override fun has4G(): Boolean {
        TODO("Not yet implemented")
    }

    override fun setSystemProperties(key: String, value: String): String? {
        executeSuCommand("setprop $key $value")
        return getSystemProperties(key)
    }

    override fun getName(): String? {
        return "通用机型（" + getModel() + "）"
    }

    override fun electrify4GModel() {
        TODO("Not yet implemented")
    }

    override fun setLcdLightStatus(isOpen: Boolean) {
        TODO("Not yet implemented")
    }

    override fun getSerialPort(): String {
        TODO("Not yet implemented")
    }

    override fun setBrightness(resolver: ContentResolver?, brightness: Int) {
        TODO("Not yet implemented")
    }

    override fun checkOnOffTime(isCheck: Boolean, isShowToast: Boolean, toastMsg: String?) {
        TODO("Not yet implemented")
    }

    override fun checkOnOffTime(isCheck: Boolean) {
        TODO("Not yet implemented")
    }

    override fun getNameplate(): String? {
        return "无"
    }

    override fun outage4GModel() {
        TODO("Not yet implemented")
    }

    override fun executeSuCommand(cmd: String) {
        if (isRoot()) {
            getInfoByRunSuCmd(cmd)
        } else {
            execCommand(cmd)
        }
    }

    override fun getInfoBySuCommand(cmd: String): String? {
        return if (isRoot()) {
            getInfoByRunSuCmd(cmd)
        } else {
            execCommand(cmd)
        }
    }

    override fun setSystemTime(time: Long) {
        val cal = Time()
        cal.set(time)
        val sYear = "" + cal.year
        val sMonth: String
        sMonth = if (cal.month + 1 < 10) {
            "0" + (cal.month + 1)
        } else {
            "" + (cal.month + 1)
        }
        val sDay: String
        sDay = if (cal.monthDay < 10) {
            "0" + cal.monthDay
        } else {
            "" + cal.monthDay
        }
        val sHour: String
        sHour = if (cal.hour < 10) {
            "0" + cal.hour
        } else {
            "" + cal.hour
        }
        val sMin: String
        sMin = if (cal.minute < 10) {
            "0" + cal.minute
        } else {
            "" + cal.minute
        }
        val sSec: String
        sSec = if (cal.second < 10) {
            "0" + cal.second
        } else {
            "" + cal.second
        }
        val cmd = "date -s \"$sYear$sMonth$sDay.$sHour$sMin$sSec\""
        executeSuCommand(cmd)
    }

    override fun getUniqueDeviceCode(): String? {
        if (TextUtils.isEmpty(mUuid)) {
            mUuid = getContent(UUID_PATH)
            if (TextUtils.isEmpty(mUuid)) {
                mUuid = generateUUID(Build.getSerial())
            }
        }
        return mUuid
    }

    /**
     * 重新生成新的uuid
     *
     * @return
     */
    private fun generateUUID(cpuSerial: String): String {
        val board = Build.BOARD
        val hardware = Build.HARDWARE
        val model = getModel()
        val mac = getLocalMac()
        if (TextUtils.equals("02:00:00:00:00:00", mac)) {
            Log.d(TAG, "this machine mac is 02:00:00:00:00:00")
        }
        val mDevId = "ck$board$hardware$model$mac".toUpperCase()
        val uuid =
            UUID(cpuSerial.hashCode().toLong(), (mDevId.hashCode() shl 32 or mDevId.hashCode()).toLong()).toString()
        FileTool.createNewFile(UUID_PATH, uuid)
        return uuid
    }

    override fun isRoot(): Boolean {
        var root = false
        try {
            root = !(!File("/system/bin/su").exists() && !File("/system/xbin/su").exists())
        } catch (var2: Exception) {
            Log.d("TAG", "isRoot " + var2.message)
        }
        return root
    }

    override fun getResolutions(screenNum: Int): String? {
        val displays = getDisplays()
        var resolutions = ""
        when (screenNum) {
            1 -> for (display in displays) {
                if (display.displayId == 0) {
                    resolutions = getDisplayWidth(display).toString() + "x" + getDisplayHeight(display)
                }
            }
            else -> {
                for (display in displays) {
                    resolutions += getDisplayWidth(display).toString() + "x" + getDisplayHeight(display) + ","
                }
                resolutions =
                    if (TextUtils.isEmpty(resolutions)) "" else resolutions.substring(0, resolutions.length - 1)
            }
        }
        if (TextUtils.isEmpty(resolutions)) {
            resolutions = "1920x1080"
        }
        return resolutions
    }

    override fun getTemperature(): String? {
        return ""
    }

    override fun getFirstLine(filePath: String?): String {
        return try {
            val fis = FileInputStream(File(filePath))
            //包装一个一行行读取的流
            val bufferedReader = BufferedReader(InputStreamReader(fis))
            //取到所有的内存信息
            val memTotal = bufferedReader.readLine()
            memTotal.trim { it <= ' ' }
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    override fun firstLine2Number(firstLine: String): String {
        val sb = StringBuffer()
        for (c in firstLine.toCharArray()) {
            if (c >= '0' && c <= '9') {
                sb.append(c)
            }
        }
        return sb.toString()
    }

    override fun getProductType(): String? {
        return ""
    }

    override fun getHumidity(): String? {
        return ""
    }

    override fun getTotalExternalMemorySize(): String? {
        return java.lang.String.valueOf(FileSizeUtil.getTotalExternalMemorySize() / 1024 / 1024)
    }

    override fun getAvailableExternalMemorySize(): String? {
        return java.lang.String.valueOf(FileSizeUtil.getAvailableExternalMemorySize() / 1024 / 1024)
    }

    @SuppressLint("MissingPermission")
    override fun getIMSI(): String? {
        val imsi = SimUtil.getSimOperator(context, 0)
        return if (TextUtils.isEmpty(imsi)) "" else imsi
    }

    override fun setTimingSwitch(onTime: String?, offTime: String?): Boolean {
        return false
    }

    override fun installApk(filePath: String?) {
        executeSuCommand("pm install -r $filePath")
    }

    override fun clearTimingSwitch() {}

    override fun screenCap(displayId: Int, pngFileName: String?) {
        executeSuCommand(
            String.format(
                Locale.CHINESE,
                "screencap -p -d %d %s",
                displayId,
                pngFileName
            )
        )
    }

    override fun screenCap(pngFileName: String?) {
        screenCap(0, pngFileName)
    }

    override fun updateKeepRunningFile() {}

    override fun getKeepRunningFile(): String? {
        return null
    }

    override fun getKeepBackgroundFile(): String? {
        return null
    }

    /**
     * 屏幕参数
     *
     * @return
     */
    @SuppressLint("NewApi")
    private fun getDisPlayMetrics(display: Display): DisplayMetrics? {
        val metrics = DisplayMetrics()
        display.getRealMetrics(metrics)
        return metrics
    }

    /**
     * 执行系统权限命令（待验证）
     *
     * @param command
     * @return
     */
    private fun execCommand(command: String): String? {
        if (TextUtils.isEmpty(command)) {
            return ""
        }
        val process: Process
        val inputStream: InputStream
        val bufferReader: BufferedReader
        val results = StringBuilder()
        try {
            process = Runtime.getRuntime().exec(command)
            inputStream = process.inputStream
            bufferReader = BufferedReader(InputStreamReader(inputStream))
            var readLine: String?
            while (bufferReader.readLine().also { readLine = it } != null) {
                results.append(readLine)
            }
            process.waitFor()
        } catch (e: IOException) {
        } catch (e: InterruptedException) {
        }
        return results.toString().trim { it <= ' ' }
    }

    /**
     * 执行su命令
     *
     * @param cmd
     * @return
     */
    private fun getInfoByRunSuCmd(cmd: String): String? {
        var process: Process? = null
        var os: DataOutputStream? = null
        var `is`: DataInputStream? = null
        var out = ""
        try {
            process = if (File("/system/bin/su").exists()) {
                Runtime.getRuntime().exec("/system/bin/su")
            } else if (File("/system/xbin/su").exists()) {
                Runtime.getRuntime().exec("/system/xbin/su")
            } else {
                Runtime.getRuntime().exec("su")
            }
            os = DataOutputStream(process.outputStream)
            os.writeBytes(
                """
                    $cmd
                    
                    """.trimIndent()
            )
            os.writeBytes("exit\n")
            os.flush()
            val aa = process.waitFor()
            `is` = DataInputStream(process.inputStream)
            val buffer = ByteArray(`is`.available())
            `is`.read(buffer)
            out = String(buffer)
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            try {
                os?.close()
                `is`?.close()
                process!!.destroy()
            } catch (e: Exception) {
            }
        }
        return if (TextUtils.isEmpty(out)) {
            out
        } else out.trim { it <= ' ' }
    }

    private fun getContent(file: String): String? {
        val sb = StringBuilder()
        if (FileTool.isFileExist(file)) {
            try {
                val fileReader = FileReader(file)
                val buf = BufferedReader(fileReader)
                var line: String? = ""
                while (buf.readLine().also { line = it } != null) {
                    sb.append(line)
                }
                fileReader.close()
                buf.close()
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return sb.toString()
    }
}